home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / oort / gameio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  27.4 KB  |  1,335 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*------------------------------------------------------------------------------
  18.  *
  19.  * OORT - gameio.c - Routines for game i/o.
  20.  *
  21.  * $Id: gameio.c,v 1.4 1994/01/28 00:18:20 mtj Exp $
  22.  * 
  23.  * Chris Fouts - May, 1993.
  24.  * 
  25.  *----------------------------------------------------------------------------*/
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <string.h>
  31. #include <netdb.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34. #include <sys/socket.h>
  35. #include <netinet/in.h>
  36.  
  37. #include <Performer/pf.h>
  38.  
  39. #include "oort.h"
  40. #include "gameio.h"
  41. #include "dashboard.h"
  42. #include "explosion.h"
  43. #include "sound.h"
  44. #include "multicast.h"
  45.  
  46. #define    MAX_ACTIVITY    100
  47. #define    END_OF_FRAME    (-1)
  48.  
  49.  
  50. /* BEGIN PROTOTYPES -S gameio.c */
  51. static void     demoIn( void ) ;
  52. static void     displayNotice( Notice *notice ) ;
  53. static void     fileIn( void ) ;
  54. static void     fileOut( void ) ;
  55. static void     initializeInputFile( char *name ) ;
  56. static void     initializeNetwork( char *servName, int defaultPort ) ;
  57. static void     initializeOutputFile( char *name ) ;
  58. static void     networkIn( void ) ;
  59. static void     networkOut( void ) ;
  60. static void     noOp( void ) ;
  61. static void     processPlayerPacket( Player *input ) ;
  62. static void     processPlayers( void ) ;
  63. static void     processSelfInDemo( Player *input ) ;
  64. static int      readRestOfFilePacket( void *packet, int size ) ;
  65. static void     setName( void ) ;
  66. static void     updatePlayers( void ) ;
  67. /* END PROTOTYPES -S gameio.c */
  68.  
  69. /*
  70.  * The following is not prototyped anywhere.
  71.  */
  72. long    gethostid( void ) ;
  73.  
  74.  
  75.  
  76. extern int            freezeTape ;
  77. extern int            timeToLive ;
  78. extern int            inFd ;
  79. extern int            outFd ;
  80. extern int            numberPlayers ;
  81. extern int            activity[] ;
  82. extern int            networking ;
  83. extern int            demoMode ;
  84. extern int            debugOn ;
  85. extern int            selfStatus ;
  86. extern int            newSelfStatus ;
  87. extern char            *basename ;
  88. extern char            playerName[] ;
  89. extern pfMatrix            playerMatrix[] ;
  90. extern pfGroup            *vehicle[N_TEAMS] ;
  91. extern pfDCS            *trike[] ;
  92. extern pfGroup            *trikeSwitch[] ;
  93. extern pfGroup            *shield ;
  94. extern char            *inName ;
  95. extern char            *outName ;
  96. extern float            gameTime ;
  97. extern float            eTime ;
  98. extern float            speed ;
  99. extern float            power ;
  100. extern float            shields ;
  101. extern float            laser ;
  102. extern float            laserCharge ;
  103. extern float            topSpeed ;
  104. extern Player            player[] ;
  105. extern float            deadTime[] ;
  106. extern pfVec3            ahead ;
  107. extern pfVec3            up ;
  108. extern pfVec3            right ;
  109. extern pfVec3            velocity[] ;
  110. extern pfVec3            acceleration[] ;
  111. extern Motion            motion ;
  112. extern PacketFunction        readPackets ;
  113. extern PacketFunction        writePackets ;
  114.  
  115. static struct sockaddr_in    inAddr ;
  116. static struct sockaddr_in    outAddr ;
  117.  
  118. static float            tStamp = 0.0f ;
  119.  
  120.  
  121. /*------------------------------------------------------------------------------
  122.  * Output player positions to a file.
  123.  *----------------------------------------------------------------------------*/
  124. static void
  125. fileOut(
  126.     void
  127.     )
  128. {
  129.     int    i ;
  130.     ngMagic    eof = END_OF_FRAME ;
  131.  
  132.     PFCOPY_VEC3( player[SELF].ahead, ahead ) ;
  133.     PFCOPY_VEC3( player[SELF].right, right ) ;
  134.     PFCOPY_VEC3( player[SELF].up, up ) ;
  135.     player[SELF].time = speed / topSpeed ;
  136.  
  137.     player[SELF].status = ( player[SELF].status & 0x0f0 ) | selfStatus ;
  138.  
  139.     if( write( outFd, (void *)&eof, sizeof( eof ) ) < sizeof( eof ) )
  140.     {
  141.         perror( outName ) ;
  142.         endProgram( 0 ) ;
  143.     }
  144.  
  145.     if( write( outFd, (void *)&gameTime, sizeof( gameTime ) ) <
  146.         sizeof( gameTime ) )
  147.     {
  148.         perror( outName ) ;
  149.         endProgram( 0 ) ;
  150.     }
  151.  
  152.     for( i = numberPlayers ; i-- ; )
  153.     {
  154.         if( write( outFd, (void *)( &player[i] ), sizeof( Player ) ) <
  155.             sizeof( Player ) )
  156.         {
  157.             perror( outName ) ;
  158.             endProgram( 0 ) ;
  159.         }
  160.     }
  161.  
  162.     player[SELF].hitId = 0 ;
  163.     player[SELF].laserStrength = 0 ;
  164. }
  165.  
  166.  
  167.  
  168. /*------------------------------------------------------------------------------
  169.  * Read of frame of players packets from a file.
  170.  *----------------------------------------------------------------------------*/
  171. static void
  172. fileIn(
  173.     void
  174.     )
  175. {
  176.     int        noCharsRead ;
  177.     GamePacket    packet ;
  178.     Player        input ;
  179.     int        st = 0 ;
  180.     int        i ;
  181.     int        number ;
  182.     static float    loopTime = 0.0f ;
  183.  
  184.     if( freezeTape )
  185.     {
  186.         loopTime += eTime ;
  187.         tStamp += eTime ;
  188.         return ;
  189.     }
  190.  
  191.     while( gameTime > tStamp )
  192.     {
  193.         i = 0 ;
  194.         do
  195.         {
  196.             if( ( noCharsRead = read( inFd, &(packet.magic),
  197.                 sizeof( packet.magic ) ) ) ==
  198.                 sizeof( packet.magic ) )
  199.             {
  200.                 switch( packet.magic )
  201.                 {
  202.                     case OORT_PLAYER :
  203.                     if( !( st = readRestOfFilePacket(
  204.                         &packet,
  205.                         sizeof( packet.player ) ) ) )
  206.                     {
  207.                         packet.player.id++ ;
  208.                         if( ngValidKeyedHost(
  209.                             packet.player.id,
  210.                             packet.player.key ) )
  211.                         {
  212.                             processPlayerPacket(
  213.                                 &(packet.player) ) ;
  214.                         }
  215.                     }
  216.                     break ;
  217.  
  218.                     case OORT_NOTICE :
  219.                     if( !( st = readRestOfFilePacket(
  220.                         &packet,
  221.                         sizeof( packet.notice ) ) ) )
  222.                     {
  223.                         if( ngValidKeyedHost(
  224.                             packet.notice.id,
  225.                             packet.notice.key ) )
  226.                         {
  227.                             displayNotice(
  228.                                 &packet.notice ) ;
  229.                         }
  230.                     }
  231.                     break ;
  232.  
  233.                     case END_OF_FRAME :
  234.                     i = 1 ;
  235.                     break ;
  236.  
  237.                     default :
  238.                     fprintf( stderr, "%s: unknown packet "
  239.                         "type received in %s.\n",
  240.                         basename, inName ) ;
  241.                     endProgram( 1 ) ;
  242.                     break ;
  243.                 }
  244.                 if( st )
  245.                 {
  246.                     fprintf( stderr, "%s: bad packet read "
  247.                         "from %s.\n", basename,
  248.                         inName ) ;
  249.                     endProgram( 1 ) ;
  250.                 }
  251.             }
  252.             else if( noCharsRead == 0 )
  253.             {
  254.                 noCharsRead = sizeof( tStamp ) +
  255.                         sizeof( ngMagic ) ;
  256.                 if( lseek( inFd, noCharsRead, SEEK_SET )
  257.                     != noCharsRead )
  258.                 {
  259.                     readPackets = noOp ;
  260.                     fprintf( stderr, "%s: could not rewind "
  261.                         "`%s'.\n", basename, inName ) ;
  262.                 }
  263.                 /*
  264.                  * If we loop through the file, need to
  265.                  * adjust the time stamp next time through by
  266.                  * the current time stamp.
  267.                  */
  268.                 loopTime = tStamp ;
  269.                 postNewMessage( "End of input file." ) ;
  270.                 while( numberPlayers > 1 )
  271.                 {
  272.                     deletePlayer( numberPlayers-1,
  273.                         "was deleted" ) ;
  274.                 }
  275.             }
  276.             else
  277.             {
  278.                 perror( inName ) ;
  279.                 endProgram( 1 ) ;
  280.             }
  281.         } while( i == 0 ) ;
  282.  
  283.         processPlayers() ;
  284.  
  285.         if( read( inFd, &tStamp, sizeof( tStamp ) ) < sizeof( tStamp ) )
  286.         {
  287.             perror( inName ) ;
  288.             endProgram( 1 ) ;
  289.         }
  290.         else
  291.         {
  292.             tStamp += loopTime ;
  293.         }
  294.     }
  295. }
  296.  
  297.  
  298.  
  299. /*------------------------------------------------------------------------------
  300.  * No op function.
  301.  *----------------------------------------------------------------------------*/
  302. static void
  303. noOp(
  304.     void
  305.     )
  306. {
  307. }
  308.  
  309.  
  310.  
  311. /*------------------------------------------------------------------------------
  312.  * Read the remainder of a game packet.
  313.  *----------------------------------------------------------------------------*/
  314. static int
  315. readRestOfFilePacket(
  316.     void    *packet,
  317.     int    size
  318.     )
  319. {
  320.     int    ncRead ;
  321.  
  322.     size -= sizeof( ngMagic ) ;
  323.  
  324.     if( ( ncRead = read( inFd, (char *)packet + sizeof( ngMagic ), size ) )
  325.         != size )
  326.     {
  327.         return( ncRead ) ;
  328.     }
  329.     else
  330.     {
  331.         return( 0 ) ;
  332.     }
  333. }
  334.  
  335.  
  336.  
  337. /*------------------------------------------------------------------------------
  338.  * Process a player packet.
  339.  *----------------------------------------------------------------------------*/
  340. static void
  341. processPlayerPacket(
  342.     Player    *input
  343.     )
  344. {
  345.     int    number ;
  346.     int    killer ;
  347.     float    dt ;
  348.     pfNode    *oldRave ;
  349.  
  350.     /*
  351.      * Either update existing player or create a new one
  352.      */
  353.     if( !( number = findPlayer( input->id ) ) )
  354.     {
  355.         if( demoMode && input->id == player[SELF].id )
  356.         {
  357.             processSelfInDemo( input ) ;
  358.             return ;
  359.         }
  360.         else
  361.         {
  362.             number = addPlayer( input ) ;
  363.             postNewMessage( "Added %s", input->name ) ;
  364.             checkId( number ) ;
  365.         }
  366.     }
  367.  
  368.     activity[number] = MAX_ACTIVITY ;
  369.  
  370.     /*
  371.      * See if status changed.
  372.      */
  373.     if( player[number].status != input->status )
  374.     {
  375.         /*
  376.          * Check for shield on going on.
  377.          */
  378.         if( !SHIELD_ON( player+number ) && SHIELD_ON( input ) )
  379.         {
  380.             if( pfGetNumChildren( trikeSwitch[number] ) > 1 )
  381.             {
  382.                 pfNodeTravMask(
  383.                     pfGetChild( trikeSwitch[number], 1 ),
  384.                     PFTRAV_DRAW, 0xffffffff, PFTRAV_SELF,
  385.                     PF_SET ) ;
  386.             }
  387.         }
  388.  
  389.         /*
  390.          * Check for starting to explode.
  391.          */
  392.         if( !EXPLODING( player+number ) && EXPLODING( input ) )
  393.         {
  394.             startExplosion( number ) ;
  395.             if( input->hitById == player[SELF].id )
  396.             {
  397.                 player[SELF].score += 1 ;
  398.                 postNewMessage( "Killed %s.", input->name ) ;
  399.                 addKill() ;
  400.             }
  401.             else if( input->hitById == 0 &&
  402.                 readPackets == networkIn )
  403.             {
  404.                 postNewMessage( "%s killed by orbital "
  405.                         "fortress.", input->name ) ;
  406.             }
  407.             else
  408.             {
  409.                 postNewMessage( "%s is dead.", input->name ) ;
  410.             }
  411.         }
  412.         /*
  413.          * Check for stopping explosion.
  414.          */
  415.         else if( EXPLODING( player+number ) && !EXPLODING( input ) )
  416.         {
  417.             endExplosion( number ) ;
  418.         }
  419.         /*
  420.          * Check for beginning to land.
  421.          */
  422.         if( ( player[number].status & OORT_ST_IN_ORBIT ) &&
  423.             ( input->status & OORT_ST_ON_GROUND ) )
  424.         {
  425.             PFSET_VEC3( acceleration[number], 0.0f, 0.0f, 0.0f ) ;
  426.             PFSET_VEC3( velocity[number], 0.0f, 0.0f, 0.0f ) ;
  427.         }
  428.     }
  429.  
  430.     /*
  431.      * See if team changed.
  432.      */
  433.     if( player[number].team != input->team )
  434.     {
  435.         oldRave = pfGetChild( trikeSwitch[number], 0 ) ;
  436.         if( pfReplaceChild( trikeSwitch[number], oldRave,
  437.             pfClone( vehicle[input->team], 0 ) ) )
  438.         {
  439.             pfDelete( oldRave ) ;
  440.             postNewMessage( "%s changed teams.", input->name ) ;
  441.         }
  442.         else
  443.         {
  444.             postNewMessage( "%s changed teams (err).",
  445.                 input->name ) ;
  446.         }
  447.     }
  448.  
  449.     /*
  450.      * Check to see if enemy hit me.
  451.      */
  452.     if( input->hitId == player[SELF].id )
  453.     {
  454.         shieldDamage( (float)input->laserStrength / 255.0f, input->id );
  455.     }
  456.  
  457.     /*
  458.      * Check for collision.
  459.      */
  460.     if( selfStatus == OORT_ST_ON_GROUND && !EXPLODING( input ) )
  461.     {
  462.         if( pfSqrDistancePt3( player[SELF].xyz, input->xyz ) <
  463.             (float)(4.0f * SHIELD_RADIUS * SHIELD_RADIUS ) )
  464.         {
  465.             postNewMessage( "Collided with %s.", input->name ) ;
  466.             shieldDamage( 0.75f, input->id ) ;
  467.             speed *= 0.5f ;
  468.         }
  469.     }
  470.  
  471.     /*
  472.      * Compute velocity for player in an effort to smooth animation
  473.      * (this is a pretty cheesy attempt).
  474.      */
  475.     if( readPackets == networkIn )
  476.     {
  477.         float    elapsedTime ;
  478.         float    sf ;
  479.         pfVec3    newVel ;
  480.  
  481.         elapsedTime = input->time - player[number].time ;
  482.         if( elapsedTime > 0.0f )
  483.         {
  484.             sf = 0.8f / elapsedTime ;
  485.         }
  486.         else
  487.         {
  488.             sf = 0.0f ;
  489.         }
  490.         PFSUB_VEC3( newVel, input->xyz, player[number].xyz ) ;
  491.         PFSCALE_VEC3( newVel, sf, newVel ) ;
  492.         PFSUB_VEC3( acceleration[number], newVel, velocity[number] ) ;
  493.         PFSCALE_VEC3( acceleration[number], sf, acceleration[number] ) ;
  494.         PFCOPY_VEC3( velocity[number], newVel ) ;
  495.     }
  496.     else
  497.     {
  498.         float    sf ;
  499.  
  500.         sf = 0.8f / eTime ;
  501.         PFSUB_VEC3( velocity[number], input->xyz, player[number].xyz ) ;
  502.         PFSCALE_VEC3( velocity[number], sf, velocity[number] ) ;
  503.     }
  504.  
  505.     /*
  506.      * Update player.
  507.      */
  508.     copyPlayer( number, input ) ;
  509. }
  510.  
  511.  
  512.  
  513. /*------------------------------------------------------------------------------
  514.  * Initialize for reading packets from a file.
  515.  *----------------------------------------------------------------------------*/
  516. static void
  517. initializeInputFile(
  518.     char    *name
  519.     )
  520. {
  521.     ngMagic    magic ;
  522.  
  523.     if( ( inFd = open( name, O_RDONLY ) ) == -1 )
  524.     {
  525.         perror( name ) ;
  526.         endProgram( 1 ) ;
  527.     }
  528.     else
  529.     {
  530.         /*
  531.          * Read in first end-of frame marker.
  532.          */
  533.         if( read( inFd, &magic, sizeof( magic ) ) != sizeof( magic ) )
  534.         {
  535.             perror( name ) ;
  536.             endProgram( 1 ) ;
  537.         }
  538.  
  539.         if( read( inFd, &tStamp, sizeof(tStamp) ) != sizeof(tStamp) )
  540.         {
  541.             perror( name ) ;
  542.             endProgram( 1 ) ;
  543.         }
  544.  
  545.         if( read( inFd, &magic, sizeof( magic ) ) != sizeof( magic ) )
  546.         {
  547.             perror( name ) ;
  548.             endProgram( 1 ) ;
  549.         }
  550.  
  551.         if( magic != OORT_PLAYER )
  552.         {
  553.             fprintf( stderr, "%s: input file `%s' is not from this"
  554.                  " version of %s.\n", basename, name,
  555.                              basename ) ;
  556.             endProgram( 1 ) ;
  557.         }
  558.         else
  559.         {
  560.             lseek( inFd, -sizeof( tStamp ), SEEK_CUR ) ;
  561.         }
  562.     }
  563.     readPackets = ( demoMode ) ? demoIn : fileIn ;
  564.  
  565.     if( demoMode )
  566.     {
  567.         postNewMessage( "Demo mode." ) ;
  568.     }
  569.     tStamp = 0.0f ;
  570. }
  571.  
  572.  
  573.  
  574. /*------------------------------------------------------------------------------
  575.  * Initialize for recording packets to a file.
  576.  *----------------------------------------------------------------------------*/
  577. static void
  578. initializeOutputFile(
  579.     char    *name
  580.     )
  581. {
  582.     if( ( outFd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0644 ) ) == -1 )
  583.     {
  584.         perror( name ) ;
  585.         endProgram( 1 ) ;
  586.     }
  587.     writePackets = fileOut ;
  588. }
  589.  
  590.  
  591.  
  592. /*------------------------------------------------------------------------------
  593.  * Initialize the communication routines.
  594.  *----------------------------------------------------------------------------*/
  595. void
  596. initCom(
  597.     void
  598.     )
  599. {
  600.     int        i ;
  601.     int        port ;
  602.     struct servent    *serv ;
  603.  
  604.     networking = 0 ;
  605.  
  606.     if( inName == NULL && outName == NULL )
  607.     {
  608.         networking = 1 ;
  609.         initializeNetwork( OORT_SERVICE, OORT_DEF_PORT ) ;
  610.     }
  611.     else
  612.     {
  613.         if( inName != NULL )
  614.         {
  615.             initializeInputFile( inName ) ;
  616.         }
  617.         else
  618.         {
  619.             readPackets = noOp ;
  620.             inFd = -1 ;
  621.         }
  622.  
  623.         if( outName != NULL )
  624.         {
  625.             initializeOutputFile( outName ) ;
  626.         }
  627.         else
  628.         {
  629.             writePackets = noOp ;
  630.             outFd = -1 ;
  631.         }
  632.     }
  633.  
  634.     if( networking )
  635.     {
  636.         player[SELF].id = gethostid() ;
  637.     }
  638.     else {
  639.         player[SELF].id = 1 ;
  640.     }
  641.  
  642.     setName() ;
  643.  
  644.     ngInit( player[SELF].id, player[SELF].key, player[SELF].name,
  645.         OORT_DROP, OORT_INVALIDATE, OORT_CENSUS, OORT_ACK, OORT_QUIT,
  646.         "/usr/tmp/oort.log" ) ;
  647. }
  648.  
  649.  
  650.  
  651. /*------------------------------------------------------------------------------
  652.  * Process the players.
  653.  *----------------------------------------------------------------------------*/
  654. static void
  655. processPlayers(
  656.     void
  657.     )
  658. {
  659.     int        i ;
  660.  
  661.     for( i = ENEMY ; i < numberPlayers ; i++ )
  662.     {
  663.         activity[i] -= 1 ;
  664.         if( activity[i] < 0 )
  665.         {
  666.             ngDropHost( player[i].id ) ;
  667.             deletePlayer( i, "was dropped" ) ;
  668.         }
  669.  
  670.         playerMatrix[i][0][0] = player[i].right[0] ;
  671.         playerMatrix[i][0][1] = player[i].right[1] ;
  672.         playerMatrix[i][0][2] = player[i].right[2] ;
  673.  
  674.         playerMatrix[i][1][0] = player[i].ahead[0] ;
  675.         playerMatrix[i][1][1] = player[i].ahead[1] ;
  676.         playerMatrix[i][1][2] = player[i].ahead[2] ;
  677.  
  678.         playerMatrix[i][2][0] = player[i].up[0] ;
  679.         playerMatrix[i][2][1] = player[i].up[1] ;
  680.         playerMatrix[i][2][2] = player[i].up[2] ;
  681.  
  682.         playerMatrix[i][3][0] = player[i].xyz[0] ;
  683.         playerMatrix[i][3][1] = player[i].xyz[1] ;
  684.         playerMatrix[i][3][2] = player[i].xyz[2] ;
  685.  
  686.         pfDCSMat( trike[i], playerMatrix[i] ) ;
  687.  
  688.         if( EXPLODING( player+i ) )
  689.         {
  690.             setExplosionFrame( i, gameTime - deadTime[i] ) ;
  691.         }
  692.     }
  693. }
  694.  
  695.  
  696.  
  697. /*------------------------------------------------------------------------------
  698.  * Set the player name.
  699.  *----------------------------------------------------------------------------*/
  700. static void
  701. setName(
  702.     void
  703.     )
  704. {
  705.     char    *name ;
  706.  
  707.     if( strlen( playerName ) == 0 )
  708.     {
  709.         if( ( name = getenv( "OORT_ID" ) ) != NULL )
  710.         {
  711.             strncpy( playerName, name, NAMELEN ) ;
  712.         }
  713.         else
  714.         {
  715.             cuserid( playerName ) ;
  716.         }
  717.     }
  718.     strncpy( player[SELF].name, playerName, NAMELEN ) ;
  719.     player[SELF].name[NAMELEN-1] = '\0' ;
  720. }
  721.  
  722.  
  723.  
  724. /*------------------------------------------------------------------------------
  725.  * Send out a packet, either to the net, to a file, or nothting.
  726.  *----------------------------------------------------------------------------*/
  727. void
  728. sendOut(
  729.     void    *buf,
  730.     int    size
  731.     )
  732. {
  733.     if( writePackets == networkOut )
  734.     {
  735.         sendToNetwork( buf, size ) ;
  736.     }
  737.     else if( writePackets == fileOut )
  738.     {
  739.         sendToFile( buf, size ) ;
  740.     }
  741. }
  742.  
  743.  
  744.  
  745. /*------------------------------------------------------------------------------
  746.  * Write a packet to a file.
  747.  *----------------------------------------------------------------------------*/
  748. void
  749. sendToFile(
  750.     void    *buf,
  751.     int    size
  752.     )
  753. {
  754.     int noCharsSent ;
  755.  
  756.     noCharsSent = write( outFd, buf, size ) ;
  757.     if( noCharsSent < size )
  758.     {
  759.         perror( "sendToFile" ) ;
  760.         endProgram( 0 ) ;
  761.     }
  762. }
  763.  
  764.  
  765.  
  766. /*------------------------------------------------------------------------------
  767.  * Write a packet to the network.
  768.  *----------------------------------------------------------------------------*/
  769. void
  770. sendToNetwork(
  771.     char    *buf,
  772.     int    size
  773.     )
  774. {
  775.     int noCharsSent ;
  776.  
  777.     noCharsSent = sendto( outFd, buf, size, 0, &outAddr, sizeof(outAddr) ) ;
  778.     if( noCharsSent < size ) {
  779.         perror( "sendToNetwork" ) ;
  780.         endProgram( 0 ) ;
  781.         }
  782. }
  783.  
  784.  
  785.  
  786. /*------------------------------------------------------------------------------
  787.  * Write packets out to network.
  788.  *----------------------------------------------------------------------------*/
  789. static void
  790. networkOut(
  791.     void
  792.     )
  793. {
  794.     int noCharsSent ;
  795.  
  796.     PFCOPY_VEC3( player[SELF].ahead, ahead ) ;
  797.     PFCOPY_VEC3( player[SELF].right, right ) ;
  798.     PFCOPY_VEC3( player[SELF].up, up ) ;
  799.     player[SELF].time = gameTime ;
  800.  
  801.     noCharsSent = sendto( outFd, (char *)(&player[SELF]),
  802.             sizeof( Player ), 0, &outAddr, sizeof( outAddr ) ) ;
  803.     if( noCharsSent < sizeof( Player ) ) {
  804.         perror( "networkOut" ) ;
  805.         endProgram( 0 ) ;
  806.         }
  807.  
  808.     player[SELF].hitId = 0 ;
  809. }
  810.  
  811.  
  812.  
  813. /*------------------------------------------------------------------------------
  814.  * Initialize the network for multicasting.
  815.  *----------------------------------------------------------------------------*/
  816. static void
  817. initializeNetwork(
  818.     char    *servName,
  819.     int    defaultPort
  820.     )
  821. {
  822.     int        port ;
  823.     struct servent    *serv ;
  824.  
  825.     if( ( serv = getservbyname( servName, NULL ) ) == NULL )
  826.     {
  827.         fprintf( stderr, "Can't find udp service \"%s\"\n", servName ) ;
  828.         fprintf( stderr, "To run over the network, you must have the "
  829.             "following line\n" ) ;
  830.         fprintf( stderr, "in your /etc/services file.\n\n" ) ;
  831.         fprintf( stderr, "%s\t%d/udp\n\n", servName, defaultPort ) ;
  832.         port = defaultPort ;
  833.     }
  834.     else
  835.     {
  836.         port = serv->s_port ;
  837.     }
  838.  
  839.     if( timeToLive < NG_MIN_TTL || timeToLive > NG_MAX_TTL )
  840.     {
  841.         fprintf( stderr, "Specified time-to-live (%d) does not fall "
  842.             "within acceptable range (%d - %d).\n", timeToLive,
  843.             NG_MIN_TTL, NG_MAX_TTL ) ;
  844.         fprintf( stderr, "The default value of %d will be used.\n",
  845.             NG_DEFAULT_TTL ) ;
  846.         timeToLive = NG_DEFAULT_TTL ;
  847.     }
  848.  
  849.     if( ( inFd = openMulticastSocket( &inAddr, port, timeToLive, 0,
  850.                     OORT_GROUP, NULL, "r" ) ) < 0 )
  851.     {
  852.         endProgram( 1 ) ;
  853.     }
  854.     readPackets = networkIn ;
  855.  
  856.     /*
  857.      * Turn on non-blocking I/O
  858.      */
  859.     if( fcntl( inFd, F_SETFL, FNDELAY ) < 0 ) {
  860.         perror( "fcntl F_SETFL, FNDELAY" ) ;
  861.         endProgram( 1 ) ;
  862.         }
  863.  
  864.     if( ( outFd = openMulticastSocket( &outAddr, port, timeToLive, 0,
  865.                     OORT_GROUP, NULL, "w" ) ) < 0 )
  866.     {
  867.         endProgram( 1 ) ;
  868.     }
  869.     writePackets = networkOut ;
  870. }
  871.  
  872.  
  873.  
  874. /*------------------------------------------------------------------------------
  875.  * Read packets from the network.
  876.  *----------------------------------------------------------------------------*/
  877. static void
  878. networkIn(
  879.     void
  880.     )
  881. {
  882.     int        noCharsReceived ;
  883.     int        id ;
  884.     GamePacket    packet ;
  885.     int        st = 0 ;
  886.     int        number ;
  887.     int        inAddrLen ;
  888.     int        socket_empty = 0 ;
  889.     static int    newer = 0 ;
  890.  
  891.     updatePlayers() ;
  892.  
  893.     while( !socket_empty ) {
  894.         noCharsReceived = recvfrom( inFd, (char *)(&packet),
  895.                   sizeof(GamePacket), 0, &inAddr, &inAddrLen ) ;
  896.         if( noCharsReceived < 0 && errno == EWOULDBLOCK )
  897.         {
  898.             socket_empty = 1 ;
  899.         }
  900.         else
  901.         {
  902.             switch( packet.magic )
  903.             {
  904.                 case OORT_PLAYER :
  905.                 if( noCharsReceived == sizeof( packet.player ) )
  906.                 {
  907.                     if( ngValidHost( packet.player.id ) )
  908.                     {
  909.                         processPlayerPacket(
  910.                             &(packet.player) ) ;
  911.                     }
  912.                     /*
  913.                      * New player, send out acknowledge
  914.                      * packet.
  915.                      */
  916.                     else if( numberPlayers < MAXPLAYERS )
  917.                     {
  918.                         ngAcknowledge( packet.player.id,
  919.                             packet.player.key ) ;
  920.                     }
  921.                 }
  922.                 else
  923.                 {
  924.                     st = sizeof( packet.player ) ;
  925.                 }
  926.                 break ;
  927.  
  928.                 case OORT_QUIT :
  929.                 if( noCharsReceived == sizeof( struct ngAck ) )
  930.                 {
  931.                     number = findPlayer( packet.ack.id ) ;
  932.                     if( number > 0 )
  933.                     {
  934.                         ngRemoveHost( packet.ack.id ) ;
  935.                         deletePlayer( number, "quit" ) ;
  936.                     }
  937.                     else
  938.                     {
  939.                         ngQuitHost( packet.ack.id ) ;
  940.                     }
  941.                 }
  942.                 else
  943.                 {
  944.                     st = sizeof( struct ngAck ) ;
  945.                 }
  946.                 break ;
  947.  
  948.                 case OORT_ACK :
  949.                 if( noCharsReceived == sizeof( struct ngAck ) )
  950.                 {
  951.                     /*
  952.                      * If acknowledging SELF, add to list
  953.                      * of valid hosts.
  954.                      */
  955.                     if( packet.ack.ackId ==
  956.                         player[SELF].id )
  957.                     {
  958.                         ngValidKeyedHost( packet.ack.id,
  959.                             packet.ack.key ) ;
  960.                         ngAcknowledge( packet.player.id,
  961.                             packet.player.key ) ;
  962.                     }
  963.                 }
  964.                 else
  965.                 {
  966.                     st = sizeof( struct ngAck ) ;
  967.                 }
  968.                 break ;
  969.  
  970.                 case OORT_DROP :
  971.                 if( noCharsReceived == sizeof( struct ngAck ) )
  972.                 {
  973.                     id = packet.ack.id ;
  974.                     /*
  975.                      * If dropping SELF, note dropped
  976.                      * status with host.
  977.                      */
  978.                     if( packet.ack.ackId ==
  979.                         player[SELF].id &&
  980.                         ngValidHost( id ) )
  981.                     {
  982.                         ngDroppedByHost( id ) ;
  983.                         number = findPlayer( id ) ;
  984.                         if( number > 0 )
  985.                         {
  986.                             deletePlayer( number,
  987.                                 "was dropped" );
  988.                         }
  989.                     }
  990.                 }
  991.                 else
  992.                 {
  993.                     st = sizeof( struct ngAck ) ;
  994.                 }
  995.                     break ;
  996.  
  997.                 case OORT_INVALIDATE :
  998.                 if( noCharsReceived == sizeof( struct ngAck ) )
  999.                 {
  1000.                     id = packet.ack.id ;
  1001.                     /*
  1002.                      * If invalidating SELF, invalidate in
  1003.                      * kind.
  1004.                      */
  1005.                     if( packet.ack.ackId ==
  1006.                         player[SELF].id &&
  1007.                         ngValidHost( id ) )
  1008.                     {
  1009.                         ngDprintf( "%s: got invalidate"
  1010.                             " packet from %s\n",
  1011.                             ngPrintTime(),
  1012.                             ngHostNameFromId(id) ) ;
  1013.                         ngInvalidateHost( id ) ;
  1014.                         number = findPlayer( id ) ;
  1015.                         if( number > 0 )
  1016.                         {
  1017.                             deletePlayer( number,
  1018.                                 "was dropped" );
  1019.                         }
  1020.                     }
  1021.                 }
  1022.                 else
  1023.                 {
  1024.                     st = sizeof( struct ngAck ) ;
  1025.                 }
  1026.                 break ;
  1027.  
  1028.                 case OORT_NOTICE :
  1029.                 if( noCharsReceived == sizeof( Notice ) )
  1030.                 {
  1031.                     if( ngValidKeyedHost(
  1032.                         packet.notice.id,
  1033.                         packet.notice.key ) )
  1034.                     {
  1035.                         displayNotice(
  1036.                             &packet.notice ) ;
  1037.                     }
  1038.                 }
  1039.                 else
  1040.                 {
  1041.                     st = sizeof( Notice ) ;
  1042.                 }
  1043.                 break ;
  1044.  
  1045.  
  1046.                 default :
  1047.                 if( packet.magic > OORT_PLAYER &&
  1048.                     ( packet.magic & 0xffffff00 ) ==
  1049.                     ( OORT_PLAYER & 0xffffff00) &&
  1050.                     newer == 0 )
  1051.                 {
  1052.                     newer = 1 ;
  1053.                     printf( "\n\nAn newer version of %s is"
  1054.                         " being played on the net.\n\n",
  1055.                     basename ) ;
  1056.                 }
  1057.                 break ;
  1058.             }
  1059.             if( st )
  1060.             {
  1061.                 fprintf( stderr, "received odd packet size of "
  1062.                     "%d instead of %d! (id = 0x%08x)\n",
  1063.                     noCharsReceived, st, packet.magic ) ;
  1064.                 st = 0 ;
  1065.             }
  1066.         }
  1067.     }
  1068.  
  1069.     processPlayers() ;
  1070. }
  1071.  
  1072.  
  1073.  
  1074. /*------------------------------------------------------------------------------
  1075.  * Update players positions based on last computed velocity (allows smooth
  1076.  * movement between machines running at different framerates).
  1077.  *----------------------------------------------------------------------------*/
  1078. static void
  1079. updatePlayers(
  1080.     void
  1081.     )
  1082. {
  1083.     int    i ;
  1084.  
  1085.     for( i = ENEMY ; i < numberPlayers ; i++ )
  1086.     {
  1087.         player[i].xyz[0] += eTime * velocity[i][0] ;
  1088.         player[i].xyz[1] += eTime * velocity[i][1] ;
  1089.         player[i].xyz[2] += eTime * velocity[i][2] ;
  1090.     }
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /*------------------------------------------------------------------------------
  1096.  * Read of frame of players packets from a file and set view to that of the
  1097.  * first vehicle.
  1098.  *----------------------------------------------------------------------------*/
  1099. static void
  1100. demoIn(
  1101.     void
  1102.     )
  1103. {
  1104.     int        noCharsRead ;
  1105.     GamePacket    packet ;
  1106.     Player        input ;
  1107.     int        st = 0 ;
  1108.     int        i ;
  1109.     int        number ;
  1110.     static float    loopTime = 0.0f ;
  1111.  
  1112.     if( freezeTape )
  1113.     {
  1114.         loopTime += eTime ;
  1115.         tStamp += eTime ;
  1116.         return ;
  1117.     }
  1118.  
  1119.     while( gameTime > tStamp )
  1120.     {
  1121.         i = 0 ;
  1122.         do
  1123.         {
  1124.             if( ( noCharsRead = read( inFd, &(packet.magic),
  1125.                 sizeof( packet.magic ) ) ) ==
  1126.                 sizeof( packet.magic ) )
  1127.             {
  1128.                 switch( packet.magic )
  1129.                 {
  1130.                     case OORT_PLAYER :
  1131.                     if( !( st = readRestOfFilePacket(
  1132.                         &packet,
  1133.                         sizeof( packet.player ) ) ) )
  1134.                     {
  1135.                         if( ngValidKeyedHost(
  1136.                             packet.player.id,
  1137.                             packet.player.key ) )
  1138.                         {
  1139.                             processPlayerPacket(
  1140.                                 &(packet.player) ) ;
  1141.                         }
  1142.                     }
  1143.                     break ;
  1144.  
  1145.                     case OORT_NOTICE :
  1146.                     if( !( st = readRestOfFilePacket(
  1147.                         &packet,
  1148.                         sizeof( packet.notice ) ) ) )
  1149.                     {
  1150.                         if( ngValidKeyedHost(
  1151.                             packet.notice.id,
  1152.                             packet.notice.key ) )
  1153.                         {
  1154.                             displayNotice(
  1155.                                 &packet.notice ) ;
  1156.                         }
  1157.                     }
  1158.                     break ;
  1159.  
  1160.                     case END_OF_FRAME :
  1161.                     i = 1 ;
  1162.                     break ;
  1163.  
  1164.                     default :
  1165.                     fprintf( stderr, "%s: unknown packet "
  1166.                         "type received in %s.\n",
  1167.                         basename, inName ) ;
  1168.                     endProgram( 1 ) ;
  1169.                     break ;
  1170.                 }
  1171.                 if( st )
  1172.                 {
  1173.                     fprintf( stderr, "%s: bad packet read "
  1174.                         "from %s.\n", basename,
  1175.                         inName ) ;
  1176.                     endProgram( 1 ) ;
  1177.                 }
  1178.             }
  1179.             else if( noCharsRead == 0 )
  1180.             {
  1181.                 noCharsRead = sizeof( tStamp ) +
  1182.                         sizeof( ngMagic ) ;
  1183.                 if( lseek( inFd, noCharsRead, SEEK_SET )
  1184.                     != noCharsRead )
  1185.                 {
  1186.                     readPackets = noOp ;
  1187.                     fprintf( stderr, "%s: could not rewind "
  1188.                         "`%s'.\n", basename, inName ) ;
  1189.                 }
  1190.                 /*
  1191.                  * If we loop through the file, need to
  1192.                  * adjust the time stamp next time through by
  1193.                  * the current time stamp.
  1194.                  */
  1195.                 loopTime = tStamp ;
  1196.                 postNewMessage( "End of input file." ) ;
  1197.                 while( numberPlayers > 1 )
  1198.                 {
  1199.                     deletePlayer( numberPlayers-1,
  1200.                         "was deleted" ) ;
  1201.                 }
  1202.             }
  1203.             else
  1204.             {
  1205.                 perror( inName ) ;
  1206.                 endProgram( 1 ) ;
  1207.             }
  1208.         } while( i == 0 ) ;
  1209.  
  1210.         processPlayers() ;
  1211.  
  1212.         if( ( noCharsRead = read( inFd, &tStamp, sizeof( tStamp ) ) )
  1213.              < sizeof( tStamp ) )
  1214.         {
  1215.             perror( inName ) ;
  1216.             endProgram( 1 ) ;
  1217.         }
  1218.         else
  1219.         {
  1220.             tStamp += loopTime ;
  1221.         }
  1222.     }
  1223.  
  1224.     PFCOPY_VEC3( motion.cg, player[SELF].xyz ) ;
  1225.     PFCOPY_VEC3( ahead, player[SELF].ahead ) ;
  1226.     PFCOPY_VEC3( right, player[SELF].right ) ;
  1227.     PFCOPY_VEC3( up, player[SELF].up ) ;
  1228.  
  1229.     newSelfStatus = player[SELF].status & 0x0f ;
  1230. }
  1231.  
  1232.  
  1233.  
  1234. /*------------------------------------------------------------------------------
  1235.  * Process player packet for self in demo mode.
  1236.  *----------------------------------------------------------------------------*/
  1237. static void
  1238. processSelfInDemo(
  1239.     Player    *input
  1240.     )
  1241. {
  1242.     /*
  1243.      * Determine speed.
  1244.      */
  1245.     speed = player[SELF].time * topSpeed ;
  1246.  
  1247.     /*
  1248.      * Check for shield on going on.
  1249.      */
  1250.     if( !SHIELD_ON( player+SELF ) && SHIELD_ON( input ) )
  1251.     {
  1252.         shieldDamage( ( shields > 0.5f ) ? 0.5f : shields, 0 ) ;
  1253.     }
  1254.  
  1255.     /*
  1256.      * Check for starting to explode.
  1257.      */
  1258.     if( !EXPLODING( player+SELF ) && EXPLODING( input ) )
  1259.     {
  1260.         blowUpSelf( input->hitById ) ;
  1261.     }
  1262.  
  1263.     if( player[SELF].laserStrength )
  1264.     {
  1265.         sfx( SFX_FIRE ) ;
  1266.         if( laser > laserCharge )
  1267.         {
  1268.             laser -= laserCharge ;
  1269.         }
  1270.         else
  1271.         {
  1272.             laser = 0.0f ;
  1273.         }
  1274.     }
  1275.  
  1276.     copyPlayer( SELF, input ) ;
  1277.  
  1278.     return ;
  1279. }
  1280.  
  1281.  
  1282.  
  1283. /*------------------------------------------------------------------------------
  1284.  * Send out a message.
  1285.  *----------------------------------------------------------------------------*/
  1286. void
  1287. mailMessage(
  1288.     char    team,
  1289.     char    *msg
  1290.     )
  1291. {
  1292.     Notice    notice ;
  1293.  
  1294.     notice.magic = OORT_NOTICE ;
  1295.     notice.id = player[SELF].id ;
  1296.     notice.key = player[SELF].key ;
  1297.     notice.team = team ;
  1298.     strncpy( notice.msg, msg, sizeof( notice.msg ) ) ;
  1299.     notice.msg[MAX_MSG_SIZE-1] = '\0' ;
  1300.  
  1301.     sendOut( ¬ice, sizeof( notice ) ) ;
  1302. }
  1303.  
  1304.  
  1305.  
  1306. /*------------------------------------------------------------------------------
  1307.  * Display a notice that has arrived if it's addressed to me.
  1308.  *----------------------------------------------------------------------------*/
  1309. static void
  1310. displayNotice(
  1311.     Notice    *notice
  1312.     )
  1313. {
  1314.     int    n ;
  1315.  
  1316.     n = findPlayer( notice->id ) ;
  1317.  
  1318.     if( notice->team == MAIL_ALL )
  1319.     {
  1320.         sfx( SFX_NEWMAIL ) ;
  1321.         postNewMessage( "Broadcast message from %s:", player[n].name ) ;
  1322.     }
  1323.     else if( notice->team == player[SELF].team )
  1324.     {
  1325.         sfx( SFX_NEWMAIL ) ;
  1326.         postNewMessage( "Team message from %s:", player[n].name ) ;
  1327.     }
  1328.     else
  1329.     {
  1330.         return ;
  1331.     }
  1332.  
  1333.     postNewMessage( "%s", notice->msg ) ;
  1334. }
  1335.